﻿using NetFwTypeLib;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using FxSuperCore.FxSupperCore;
using ThreadState = System.Threading.ThreadState;
using System.Runtime.InteropServices;
using System.Windows.Media.Imaging;
using System.Drawing.Imaging;

namespace FxSuperCore.Utils
{
	public static class CommonUtils
	{
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool SetForegroundWindow(IntPtr hWnd);

		/// <summary>
		/// 异或解密
		/// </summary>
		/// <param name="str">源字符串</param>
		/// <returns>结果字符串</returns>
		internal static string XorDecrypt(string str)
		{
			byte[] key_bytes = Encoding.UTF8.GetBytes("D89475D32EA3AXE933DBD299599EEA3E");
			byte[] bytes = Base64.Decode(str);
			for (var i = 0; i < bytes.Length; i++)
			{
				bytes[i] = (byte)(bytes[i] ^ key_bytes[i % key_bytes.Length]);
			}

			return Encoding.UTF8.GetString(bytes);
		}

		/// <summary>
		/// 异或加密
		/// </summary>
		/// <param name="str">源字符串</param>
		/// <returns>结果对象: {code: *, msg: *}</returns>
		internal static string XorEncrypt(string str)
		{
			byte[] key_bytes = Encoding.UTF8.GetBytes("D89475D32EA3AXE933DBD299599EEA3E");
			byte[] bytes = Encoding.UTF8.GetBytes(str);
			for (var i = 0; i < bytes.Length; i++)
			{
				bytes[i] = (byte)(bytes[i] ^ key_bytes[i % key_bytes.Length]);
			}

			return Encoding.UTF8.GetString(Base64.Encode(bytes));
		}

		/// <summary>
		/// md5加密
		/// </summary>
		/// <param name="str">要加密的字符串</param>
		/// <returns></returns>
		public static string MD5Encrypt(string str)
		{
			var md5 = new MD5CryptoServiceProvider();
			byte[] emailBytes = Encoding.UTF8.GetBytes(str);
			byte[] hashedEmailBytes = md5.ComputeHash(emailBytes);
			StringBuilder sb = new StringBuilder();
			foreach (var b in hashedEmailBytes)
			{
				sb.Append(b.ToString("x2").ToLower());
			}
			return sb.ToString();
		}


		/// <summary>
		/// 检测程序是否多开
		/// </summary>
		internal static bool DetectMulOpen()
		{
			Process process = Process.GetCurrentProcess();
			foreach (var p in Process.GetProcesses())
			{
				if (p.ProcessName == process.ProcessName && p.Id != process.Id)
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// 将Keys集合转为字符串形式
		/// </summary>
		/// <param name="keys">keys集合</param>
		/// <returns>目标字符串</returns>
		public static string KeysCollectToStr(List<Keys> keys)
		{
			StringBuilder sb = new StringBuilder();
			foreach (Keys key in keys)
			{
				sb.Append(key.ToString() + " + ");
			}

			string keyStr = sb.ToString();
			return keyStr.TrimEnd(' ', '+');
		}

		/// <summary>
		/// 扫描文件夹获取文件列表
		/// </summary>
		/// <param name="folderPath">文件夹路径</param>
		/// <param name="isDeep">是否采用深度扫描</param>
		/// <param name="ends">文件后缀，用于过滤文件</param>
		/// <returns></returns>
		public static List<string> ScanFolder(string folderPath, bool isDeep, params string[] ends)
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
			if (directoryInfo.Exists == false) return new List<string>(0);
			if (isDeep)
			{
				// 采用递归扫描
				List<string> fileList = new List<string>();
				RescurFileList(folderPath, ref fileList, ends);
				return fileList;
			}
			else
			{
				return directoryInfo.GetFiles()
					.Select(f => f.FullName)
					.Where(file => ends.Any(end => file.ToLower().EndsWith(end)))
					.ToList();
			}
		}

		/// <summary>
		/// 递归扫描满足条件的文件列表
		/// </summary>
		/// <param name="folderPath">开始的文件夹目录</param>
		/// <param name="fileList">返回的结果列表</param>
		/// <param name="ends">文件的结尾数组，用于过滤文件后缀名</param>
		public static void RescurFileList(string folderPath, ref List<string> fileList, params string[] ends)
		{
			if (Directory.Exists(folderPath) == false) return;
			List<string> curFileList = Directory.GetFiles(folderPath)
				.Where(file => ends.Any(end => file.ToLower().EndsWith(end)))
				.ToList();
			fileList.AddRange(curFileList);
			foreach (string directory in Directory.GetDirectories(folderPath))
			{
				RescurFileList(directory, ref fileList, ends);
			}
		}

		/// <summary>
		/// 发送GET请求
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="headerObj">请求头</param>
		/// <returns>数据</returns>
		public static string SendGet(string url, Dictionary<string, string> headers = null)
		{
			HttpWebRequest request = HttpWebRequest.CreateHttp(url);
			request.Method = "GET";
			if (headers != null)
			{
				foreach (var headersKey in headers.Keys)
				{
					string key = headersKey;
					// 设置请求头
					switch (key.ToLower())
					{
						case "user-agent":
							request.UserAgent = headers[headersKey].ToString();
							break;
						case "connection":
							request.Connection = headers[headersKey].ToString();
							break;
						case "accept":
							request.Accept = headers[headersKey].ToString();
							break;
						case "host":
							request.Host = headers[headersKey].ToString();
							break;
						case "referer":
							request.Referer = headers[headersKey].ToString();
							break;
						default:
							request.Headers[key] = headers[headersKey].ToString();
							break;
					}
				}
			}
			try
			{
				using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
				{
					string resp = sr.ReadToEnd();
					return resp;
				}
			}
			catch
			{
				return null;
			}
		}


		/// <summary>
		/// 发送表单类型的POST请求
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="dataObj">表单对</param>
		/// <param name="headersObj">请求头</param>
		/// <returns></returns>
		public static string SendPost(string url, Dictionary<string, object> data = null, Dictionary<string, object> headers = null)
		{
			HttpWebRequest request = HttpWebRequest.CreateHttp(url);
			request.Method = "POST";
			request.ContentType = "application/x-www-form-urlencoded";
			if (data != null)
			{
				StringBuilder sb = new StringBuilder("");
				foreach (var key in data.Keys)
				{
					sb.Append(key + "=" + data[key] + "&");
				}

				byte[] bytes = Encoding.UTF8.GetBytes(sb.ToString());
				using (Stream stream = request.GetRequestStream())
				{
					stream.Write(bytes, 0, bytes.Length);
					stream.Flush();
					stream.Close();
				}
			}
			if (headers != null)
			{
				foreach (var headersKey in headers.Keys)
				{
					string key = headersKey;
					// 设置请求头
					switch (key.ToLower())
					{
						case "user-agent":
							request.UserAgent = headers[headersKey].ToString();
							break;
						case "connection":
							request.Connection = headers[headersKey].ToString();
							break;
						case "accept":
							request.Accept = headers[headersKey].ToString();
							break;
						case "host":
							request.Host = headers[headersKey].ToString();
							break;
						case "referer":
							request.Referer = headers[headersKey].ToString();
							break;
						case "ContentType":
							request.ContentType = headers[headersKey].ToString();
							break;
						default:
							request.Headers[key] = headers[headersKey].ToString();
							break;
					}

				}
			}
			try
			{
				using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
				{
					string resp = sr.ReadToEnd();
					return resp;
				}
			}
			catch
			{
				return null;
			}
		}


		/// <summary>
		/// 发送请求体类型的POST请求
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="body">请求体</param>
		/// <param name="headersObj">请求头</param>
		/// <returns></returns>
		public static string SendPostByBody(string url, string body, Dictionary<string, object> headers = null)
		{
			HttpWebRequest request = HttpWebRequest.CreateHttp(url);
			request.Method = "POST";
			request.ContentType = "application/json";
			byte[] bytes = Encoding.UTF8.GetBytes(body);
			using (Stream stream = request.GetRequestStream())
			{
				stream.Write(bytes, 0, bytes.Length);
				stream.Flush();
				stream.Close();
			}
			if (headers != null)
			{
				foreach (var headersKey in headers.Keys)
				{
					string key = headersKey;
					// 设置请求头
					switch (key.ToLower())
					{
						case "user-agent":
							request.UserAgent = headers[headersKey].ToString();
							break;
						case "connection":
							request.Connection = headers[headersKey].ToString();
							break;
						case "accept":
							request.Accept = headers[headersKey].ToString();
							break;
						case "host":
							request.Host = headers[headersKey].ToString();
							break;
						case "referer":
							request.Referer = headers[headersKey].ToString();
							break;
						case "ContentType":
							request.ContentType = headers[headersKey].ToString();
							break;
						default:
							request.Headers[key] = headers[headersKey].ToString();
							break;
					}

				}
			}
			try
			{
				using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
				{
					string resp = sr.ReadToEnd();
					return resp;
				}
			}
			catch
			{
				return null;
			}
		}

		/// <summary>
		/// 时间戳转日期
		/// </summary>
		/// <param name="timespan">时间戳</param>
		public static DateTime TimespanToDatetime(double timespan)
		{
			if (timespan.ToString().Length > 10)
			{
				int n = timespan.ToString().Length - 10;
				timespan /= Math.Pow(10, n);
			}
			DateTime dateTime = new DateTime(1970, 1, 1);
			return dateTime.AddSeconds(timespan).ToLocalTime();
		}

		/// <summary>
		/// 日期转时间戳
		/// </summary>
		/// <param name="dateTime">日期</param>
		/// <returns></returns>
		public static long DatetimeToTimespan(DateTime dateTime)
		{
			DateTime startDateTime = new DateTime(1970, 1, 1);
			TimeSpan timeSpan = dateTime - startDateTime;
			return (long)timeSpan.TotalMilliseconds;
		}

		public static bool IsAbort(this Thread thread)
		{
			return (thread.ThreadState & ThreadState.AbortRequested) == ThreadState.AbortRequested;
		}

		/// <summary>
		/// 解析zip文件
		/// </summary>
		/// <param name="destinationDirectoryName">目标文件夹</param>
		/// <param name="overwrite">是否覆写已经存在的文件</param>
		/// <param name="handler">为null则解压否则执行该委托逻辑</param>
		public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, bool overwrite, Action<ZipArchiveEntry, string> handler = null)
		{
			if (source == null)
				throw new ArgumentNullException(nameof(source));
			string path1 = destinationDirectoryName != null ? Directory.CreateDirectory(destinationDirectoryName).FullName : throw new ArgumentNullException(nameof(destinationDirectoryName));
			int length = path1.Length;
			if (length != 0 && (int)path1[length - 1] != (int)Path.DirectorySeparatorChar)
				path1 += Path.DirectorySeparatorChar.ToString();
			foreach (ZipArchiveEntry entry in source.Entries)
			{
				string fullPath = Path.GetFullPath(Path.Combine(path1, entry.FullName));
				if (!fullPath.StartsWith(path1, StringComparison.OrdinalIgnoreCase))
					throw new IOException("IO_ExtractingResultsInOutside");
				if (Path.GetFileName(fullPath).Length == 0)
				{
					if (entry.Length != 0L)
						throw new IOException("IO_DirectoryNameWithData");
					Directory.CreateDirectory(fullPath);
				}
				else
				{
					Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
					if (handler == null)
					{
						entry.ExtractToFile(fullPath, overwrite);
					}
					else
					{
						handler.Invoke(entry, fullPath);
					}
				}
			}
		}

		/// <summary>
		/// 显示提示类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowTipMsg(string msg)
		{
			MessageBox.Show(msg, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		/// <summary>
		/// 显示警告类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowWarningMsg(string msg)
		{
			MessageBox.Show(msg, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
		}

		/// <summary>
		/// 显示错误类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowErrorMsg(string msg)
		{
			MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

		/// <summary>
		/// 显示提示类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowTipMsgAsync(string msg)
		{
			Task.Run(() => MessageBox.Show(msg, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information));
		}

		/// <summary>
		/// 显示警告类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowWarningMsgAsync(string msg)
		{
			Task.Run(() => MessageBox.Show(msg, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning));
		}

		/// <summary>
		/// 显示错误类型的消息
		/// </summary>
		/// <param name="msg">消息内容</param>
		public static void ShowErrorMsgAsync(string msg)
		{
			Task.Run(() => MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error));
		}

		public static void ForEachWithIndex<T>(this List<T> list, Action<T, int> func)
		{
			int index = 0;
			list.ForEach(val => func?.Invoke(val, index++));
		}


		/// <summary>
		/// 显示windows本地通知
		/// </summary>
		/// <param name="title">标题</param>
		/// <param name="msg">消息</param>
		/// <param name="type">通知类型</param>
		/// <param name="timeout">超时时间小于0则永不消失</param>
		public static async void ShowWinToast(string title, string msg, ToolTipIcon type = ToolTipIcon.Warning, int timeout = 5000)
		{
			if (timeout < 0)
			{
				timeout = 5000;
			}
			NotifyIcon notifyIcon = new NotifyIcon();
			notifyIcon.Icon = FxSupperCoreResource.fx32;
			notifyIcon.BalloonTipIcon = type;
			notifyIcon.BalloonTipText = msg;
			notifyIcon.BalloonTipTitle = title;
			notifyIcon.Visible = true;
			notifyIcon.ShowBalloonTip(timeout);
			notifyIcon.Visible = false;
			await Task.Delay(timeout);
			notifyIcon.Dispose();
		}

		/// <summary>
		/// 检测指定端口是否被占用
		/// </summary>
		/// <param name="port">端口</param>
		/// <returns>true/false</returns>
		public static bool PortInUse(int port)
		{
			bool inUse = false;
			IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
			IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

			foreach (IPEndPoint endPoint in ipEndPoints)
			{
				if (endPoint.Port == port)
				{
					inUse = true;
					break;
				}
			}

			return inUse;
		}

		/// <summary>
		/// 尝试获取一个系统可用的端口
		/// </summary>
		/// <param name="intentionPort">意向的端口号</param>
		/// <returns>获取到的端口号，失败返回0</returns>
		public static int GetCanUsePort(params int[] intentionPort)
		{
			int port = intentionPort.FirstOrDefault(p => !PortInUse(p));
			if (port > 0)
			{
				return port;
			}

			for (int i = 80; i < 65535; i++)
			{
				if (!PortInUse(i))
				{
					return i;
				}
			}

			return port;
		}

		/// <summary>
		/// 获取本机的所有可用的ipv4地址
		/// </summary>
		/// <returns>优先wifi</returns>
		public static LinkedList<string> GetIpv4Address()
		{
			LinkedList<string> ipv4AddressList = new LinkedList<string>();
			NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface net in networkInterfaces)
			{
				if (net.OperationalStatus == OperationalStatus.Up)
				{
					IPInterfaceProperties ipProperties = net.GetIPProperties();
					foreach (UnicastIPAddressInformation address in ipProperties.UnicastAddresses)
					{
						if (address.Address.AddressFamily == AddressFamily.InterNetwork)
						{
							if (net.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
							{
								ipv4AddressList.AddFirst(address.Address.ToString());
							}
							else
							{
								ipv4AddressList.AddLast(address.Address.ToString());
							}
						}
					}
				}
			}

			return ipv4AddressList;
		}

		/// <summary>
		/// 添加到防火墙规则
		/// </summary>
		/// <param name="ruleName">规则名</param>
		/// <param name="port">端口号</param>
		public static void ChangeFirewallRule(string ruleName, ushort port, bool isAdd = true)
		{
			// 创建一个新的防火墙规则对象
			INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwRule"));

			// 设置防火墙规则属性
			firewallRule.Name = ruleName;
			firewallRule.Description = $"Allow inbound traffic on port {port}";
			firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
			firewallRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
			firewallRule.LocalPorts = port.ToString();
			firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
			firewallRule.Enabled = true;

			// 获取防火墙管理器
			INetFwPolicy2 policy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));

			policy.Rules.Remove(ruleName);
			if (isAdd)
			{
				// 添加防火墙规则到入站规则集合
				policy.Rules.Add(firewallRule);
			}
		}

		/// <summary>
		/// 重启程序
		/// </summary>
		/// <param name="delay">重启延时</param>
		public static void RestartApplication(int delay = 2)
		{
			string path = Path.GetDirectoryName(Application.ExecutablePath);
			string exeName = Path.GetFileName(Application.ExecutablePath);
			Process process = new Process();
			process.StartInfo.FileName = "cmd.exe";
			process.StartInfo.Arguments = $"/c timeout /t {delay} && cd \"{path}\" && {exeName}";
			process.StartInfo.CreateNoWindow = true;
			process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
			process.StartInfo.UseShellExecute = true;
			process.StartInfo.Verb = "runas";
			process.Start();
			Application.Exit();
		}

		/// <summary>
		/// 将bitmap转为wpf的BitmapImage
		/// </summary>
		/// <returns></returns>
		public static BitmapImage ConvertBitmapToBitmapImage(System.Drawing.Bitmap bitmap)
		{
			if (bitmap == null)
				throw new ArgumentNullException(nameof(bitmap));

			using (MemoryStream memoryStream = new MemoryStream())
			{
				// 将 Bitmap 保存到内存流
				bitmap.Save(memoryStream, ImageFormat.Png);
				// 重置流的位置
				memoryStream.Position = 0;
				// 创建 BitmapImage 并从内存流加载
				BitmapImage bitmapImage = new BitmapImage();
				bitmapImage.BeginInit();
				bitmapImage.CacheOption = BitmapCacheOption.OnLoad; // 设置缓存选项
				bitmapImage.StreamSource = memoryStream;
				bitmapImage.EndInit();
				bitmapImage.Freeze(); // 冻结对象，使其不可修改
				return bitmapImage;
			}
		}
	}
}
